﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Xoohoo.Extensions;
using Xoohoo.Infrastructure;
using Xoohoo.InversionOfControl;
using Xoohoo.Models;
using Xoohoo.Services;

namespace Xoohoo
{
    public class XoohooApplication : HttpApplication
    {
        /// <summary>
        /// 初始化程序
        /// </summary>
        /// <remarks>
        /// <para>1、设置依赖关系解析器</para>
        /// <para>2、Application["bootStrappersLoaded"]，bool型；表示引导程序加载状态，
        /// 用于标识程序是否完成过初始化工作；
        /// false表示没有完成初始化工作，反之表示已经完成过。
        /// 这里将"引导程序加载状态"初始值为false。</para>
        /// <para>3、加载引导程序</para>
        /// </remarks>
        protected void Application_Start()
        {
            // 设置 IoC/DI 容器。用于替换ASP.NET MVC内置的依赖注入容器DefaultDependencyResolver
            DependencyResolver.SetResolver(new DependencyResolverFactory().CreateDependencyResolver());

            // 引导程序载入状态。当系统被首次请求时状态设置为未加载，在Load方法进行加载
            Application["bootStrappersLoaded"] = false;

            // 加载引导程序
            Load(new HttpContextWrapper(Context));
        }

        /// <summary>
        /// 卸载应用程序
        /// </summary>
        protected void Application_End()
        {
            if (Context!=null)
                Unload(new HttpContextWrapper(Context));
        }

        /// <summary>
        /// 处理AcquireRequestState事件
        /// </summary>
        /// <remarks>
        /// <para>事件在创建了事件处理程序之后引发</para>
        /// <para>主要目的是在每次请求时初始化Site、IUser、RequestContext，
        /// 并存入会话状态(HttpContext.Items)</para>
        /// </remarks>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_AcquireRequestState(object sender, EventArgs e)
        {
            //获取事件处理程序MvcHandler
            MvcHandler handler = Context.Handler as MvcHandler;

            if (handler == null) return;

            //获取所定义路由匹配的 HTTP 请求的相关信息
            RequestContext requestContext = handler.RequestContext;
            if (requestContext == null) return;

            //获取当前的依赖注入解析器
            IDependencyResolver dependencyResolver = DependencyResolver.Current;
            //获取已加载模块(Module)
            IModuleRegistry modulesLoaded = dependencyResolver.GetService<IModuleRegistry>();

            if (modulesLoaded != null)
            {
                IUser user;
                //当前模块的认证模块
                IAuthenticationModule authenticationModule = modulesLoaded.GetAuthenticationModule(requestContext.RouteData.DataTokens["ModuleName"] as string);
                if (authenticationModule != null)
                    user = authenticationModule.GetUser(requestContext);
                else
                    user = new UserAnonymous();
                Context.Items[typeof(Site).FullName] = dependencyResolver.GetService<ISiteService>().GetItem();
                Context.Items[typeof(IUser).FullName] = user;
                Context.Items[typeof(IAuthenticationModule).FullName] = authenticationModule;
                Context.Items[typeof(RequestContext).FullName] = requestContext;
            }
        }

        #region Private Static Methods

        /// <summary>
        /// 加载引导程序
        /// </summary>
        /// <param name="context">请求上下文</param>
        private static void Load(HttpContextBase context)
        {
            // 备注：实现了IBootStrapperTask接口的类，在这里称之为“引导程序”。
            // 获取所有需要加载的引导程序
            IEnumerable<IBootStrapperTask> tasks = DependencyResolver.Current.GetServices<IBootStrapperTask>();
            // 引导程序载入状态
            bool bootStrappersLoaded = (bool)context.Application["bootStrappersLoaded"];
            // bootStrapperState用于记录已经载入的引导程序的各种特有的状态值
            IDictionary<string, object> state = (IDictionary<string, object>)context.Application["bootStrapperState"];

            if (state == null)
            {
                context.Application["bootStrapperState"] = state = new Dictionary<string, object>();
            }

            // 如果引导程序已经执行过（比如Load方法是在运行时而不是系统首次被请求时被调用），
            // 进行相关的回滚清理工作。
            if (bootStrappersLoaded)
            {
                foreach (IBootStrapperTask task in tasks)
                {
                    task.Cleanup(state);
                }
            }

            // 启动所有引导程序
            foreach (IBootStrapperTask task in tasks)
            {
                task.Execute(state);
            }

            // 将引导程序载入状态设置为：已启动
            context.Application["bootStrappersLoaded"] = true;
        }

        /// <summary>
        /// 卸载引导程序
        /// </summary>
        /// <remarks>用于完成一些清理工作</remarks>
        /// <param name="context">请求上下文</param>
        private static void Unload(HttpContextBase context)
        {
            if (context != null && context.Application != null)
            {
                IDictionary<string, object> state = (IDictionary<string, object>)context.Application["bootStrapperState"];

                foreach (IBootStrapperTask task in DependencyResolver.Current.GetServices<IBootStrapperTask>())
                    task.Cleanup(state);
            }
        }

        #endregion

    }
}
